
local Sbox     = { } -- S盒
local ISbox    = { } -- 逆S盒
local Table    = { { } , { } , { } , { } } -- 混合链表
local TableInv = { { } , { } , { } , { } } -- 逆混合链表

local rCon = {  0x01000000, 0x02000000, 0x04000000, 0x08000000,
                0x10000000, 0x20000000, 0x40000000, 0x80000000,
                0x1b000000, 0x36000000, 0x6c000000, 0xd8000000,
                0xab000000, 0x4d000000, 0x9a000000, 0x2f000000 }

---奇偶效验
---@param byte integer
---@return     integer
local function byteParity( byte )
    byte = byte ~ ( byte >> 4 )
    byte = byte ~ ( byte >> 2 )
    byte = byte ~ ( byte >> 1 )
    return byte & 1
end

---仿射变换计算S-Box
---@param byte integer
---@return     integer
local function affinMap( byte )
    local mask   = 0xf8
    local result = 0
    for i = 1 , 8 do
        result = result << 1
        local parity = byteParity( byte & mask )
        result = result + parity
        local lastbit = mask & 1
        mask = ( mask >> 1 ) & 0xff
        if lastbit ~= 0 then
            mask = mask ~ 0x80
        else
            mask = mask & 0x7f
        end
    end
    return result ~ 0x63
end

---初始化Exp和Log
local exp = { }
local log = { }
do
    local a = 1
    for i = 0 , 0xfe do
        exp[i] = a
        log[a] = i
        a = ( a << 1 ) ~ a
        if a > 0xff then
            a = a ~ 0x11b
        end
    end
end

---初始化S-Box和逆S-Box
do
    for i = 0 , 255 do
        local inverse = i
        if i ~= 0 then
            if i ~= 1 then
                inverse = exp[ 0xff - log[i] ]
            end
        end
        local mapped = affinMap( inverse )
        Sbox[i]       = mapped
        ISbox[mapped] = i
    end
end

---@param number integer
---@param index  integer
---@return       integer
local function getByte( number , index )
    return ( number >> ( index * 8 ) ) & 0xff
end

---@param number integer
---@param index  integer
---@return       integer
local function putByte( number , index )
    return ( number & 0xff ) << ( index * 8 )
end

---两个对数相乘
---@param operandA integer
---@param operandB integer
---@return         integer
local function multiply( operandA , operandB )
    if operandA == 0 or operandB == 0 then
        return 0
    end
    local exponent = log[operandA] + log[operandB]
    if exponent >= 0xff then
        exponent = exponent - 0xff
    end
    return exp[exponent]
end

---初始化混合链表
do
    for x = 0 , 0xff do
        local byte     = Sbox[x]
        Table[1][x]    = putByte( multiply( 0x03 , byte ) , 0 )
                       + putByte(                  byte   , 1 )
                       + putByte(                  byte   , 2 )
                       + putByte( multiply( 0x02 , byte ) , 3 )
        Table[2][x]    = putByte(                  byte   , 0 )
                       + putByte(                  byte   , 1 )
                       + putByte( multiply( 0x02 , byte ) , 2 )
                       + putByte( multiply( 0x03 , byte ) , 3 )
        Table[3][x]    = putByte(                  byte   , 0 )
                       + putByte( multiply( 0x02 , byte ) , 1 )
                       + putByte( multiply( 0x03 , byte ) , 2 )
                       + putByte(                  byte   , 3 )
        Table[4][x]    = putByte( multiply( 0x02 , byte ) , 0 )
                       + putByte( multiply( 0x03 , byte ) , 1 )
                       + putByte(                  byte   , 2 )
                       + putByte(                  byte   , 3 )

        local byte     = ISbox[x]
        TableInv[1][x] = putByte( multiply( 0x0b , byte ) , 0 )
                       + putByte( multiply( 0x0d , byte ) , 1 )
                       + putByte( multiply( 0x09 , byte ) , 2 )
                       + putByte( multiply( 0x0e , byte ) , 3 )
        TableInv[2][x] = putByte( multiply( 0x0d , byte ) , 0 )
                       + putByte( multiply( 0x09 , byte ) , 1 )
                       + putByte( multiply( 0x0e , byte ) , 2 )
                       + putByte( multiply( 0x0b , byte ) , 3 )
        TableInv[3][x] = putByte( multiply( 0x09 , byte ) , 0 )
                       + putByte( multiply( 0x0e , byte ) , 1 )
                       + putByte( multiply( 0x0b , byte ) , 2 )
                       + putByte( multiply( 0x0d , byte ) , 3 )
        TableInv[4][x] = putByte( multiply( 0x0e , byte ) , 0 )
                       + putByte( multiply( 0x0b , byte ) , 1 )
                       + putByte( multiply( 0x0d , byte ) , 2 )
                       + putByte( multiply( 0x09 , byte ) , 3 )
    end
end

---@param word integer
---@return     integer
local function rotWord( word )
    local tmp = word & 0xff000000
    return ( word << 8 ) + ( tmp >> 24 )
end

---@param word integer
---@return     integer
local function subWord( word )
    return putByte( Sbox[getByte( word , 0 )] , 0 )
         + putByte( Sbox[getByte( word , 1 )] , 1 )
         + putByte( Sbox[getByte( word , 2 )] , 2 )
         + putByte( Sbox[getByte( word , 3 )] , 3 )
end

---混合列
---@param world integer
---@return      integer
local function invMixColumn( world )
    local byte = { }
    byte[0]    = getByte( world , 3 )
    byte[1]    = getByte( world , 2 )
    byte[2]    = getByte( world , 1 )
    byte[3]    = getByte( world , 0 )
    return putByte( ( ( ( multiply( 0x0b, byte[1] )   ~
                          multiply( 0x0d, byte[2] ) ) ~
                          multiply( 0x09, byte[3] ) ) ~
                          multiply( 0x0e, byte[0] ) ) , 3 )
         + putByte( ( ( ( multiply( 0x0b, byte[2] )   ~ 
                          multiply( 0x0d, byte[3] ) ) ~
                          multiply( 0x09, byte[0] ) ) ~
                          multiply( 0x0e, byte[1] ) ) , 2 )
         + putByte( ( ( ( multiply( 0x0b, byte[3] )   ~
                          multiply( 0x0d, byte[0] ) ) ~
                          multiply( 0x09, byte[1] ) ) ~
                          multiply( 0x0e, byte[2] ) ) , 1 )
         + putByte( ( ( ( multiply( 0x0b, byte[0] )   ~
                          multiply( 0x0d, byte[1] ) ) ~
                          multiply( 0x09, byte[2] ) ) ~
                          multiply( 0x0e, byte[3] ) ) , 0 )
end

---@param state table
---@param key   table
---@param round number
local function addRoundKey( state , key , round )
    for i = 0, 3 do
        state[i] = state[i] ~ key[round*4+i]
    end
end

---@param origState table
---@param dstState  table
local function doRound( origState , dstState )
    dstState[0] = ( ( ( Table[1][getByte( origState[0] , 3 )]   ~
                        Table[2][getByte( origState[1] , 2 )] ) ~
                        Table[3][getByte( origState[2] , 1 )] ) ~
                        Table[4][getByte( origState[3] , 0 )] )
    dstState[1] = ( ( ( Table[1][getByte( origState[1] , 3 )]   ~
                        Table[2][getByte( origState[2] , 2 )] ) ~
                        Table[3][getByte( origState[3] , 1 )] ) ~
                        Table[4][getByte( origState[0] , 0 )] )
    dstState[2] = ( ( ( Table[1][getByte( origState[2] , 3 )]   ~
                        Table[2][getByte( origState[3] , 2 )] ) ~
                        Table[3][getByte( origState[0] , 1 )] ) ~
                        Table[4][getByte( origState[1] , 0 )] )
    dstState[3] = ( ( ( Table[1][getByte( origState[3] , 3 )]   ~
                        Table[2][getByte( origState[0] , 2 )] ) ~
                        Table[3][getByte( origState[1] , 1 )] ) ~
                        Table[4][getByte( origState[2] , 0 )] )
end

---@param origState table
---@param dstState  table
local function doLastRound(origState, dstState)
    dstState[0] = putByte( Sbox[getByte( origState[0] , 3 )] , 3 )
                + putByte( Sbox[getByte( origState[1] , 2 )] , 2 )
                + putByte( Sbox[getByte( origState[2] , 1 )] , 1 )
                + putByte( Sbox[getByte( origState[3] , 0 )] , 0 )
    dstState[1] = putByte( Sbox[getByte( origState[1] , 3 )] , 3 )
                + putByte( Sbox[getByte( origState[2] , 2 )] , 2 )
                + putByte( Sbox[getByte( origState[3] , 1 )] , 1 )
                + putByte( Sbox[getByte( origState[0] , 0 )] , 0 )
    dstState[2] = putByte( Sbox[getByte( origState[2] , 3 )] , 3 )
                + putByte( Sbox[getByte( origState[3] , 2 )] , 2 )
                + putByte( Sbox[getByte( origState[0] , 1 )] , 1 )
                + putByte( Sbox[getByte( origState[1] , 0 )] , 0 )
    dstState[3] = putByte( Sbox[getByte( origState[3] , 3 )] , 3 )
                + putByte( Sbox[getByte( origState[0] , 2 )] , 2 )
                + putByte( Sbox[getByte( origState[1] , 1 )] , 1 )
                + putByte( Sbox[getByte( origState[2] , 0 )] , 0 )
end

---@param origState table
---@param dstState  table
local function doInvRound( origState , dstState )
    dstState[0] = ( ( ( TableInv[1][getByte( origState[0] , 3 )]   ~
                        TableInv[2][getByte( origState[3] , 2 )] ) ~
                        TableInv[3][getByte( origState[2] , 1 )] ) ~
                        TableInv[4][getByte( origState[1] , 0 )] )
    dstState[1] = ( ( ( TableInv[1][getByte( origState[1] , 3 )]   ~
                        TableInv[2][getByte( origState[0] , 2 )] ) ~
                        TableInv[3][getByte( origState[3] , 1 )] ) ~
                        TableInv[4][getByte( origState[2] , 0 )] )
    dstState[2] = ( ( ( TableInv[1][getByte( origState[2] , 3 )]   ~
                        TableInv[2][getByte( origState[1] , 2 )] ) ~
                        TableInv[3][getByte( origState[0] , 1 )] ) ~
                        TableInv[4][getByte( origState[3] , 0 )] )
    dstState[3] = ( ( ( TableInv[1][getByte( origState[3] , 3 )]   ~
                        TableInv[2][getByte( origState[2] , 2 )] ) ~
                        TableInv[3][getByte( origState[1] , 1 )] ) ~
                        TableInv[4][getByte( origState[0] , 0 )] )
end

---@param origState table
---@param dstState  table
local function doInvLastRound(origState, dstState)
    dstState[0] = putByte( ISbox[getByte( origState[0] , 3 )] , 3 )
                + putByte( ISbox[getByte( origState[3] , 2 )] , 2 )
                + putByte( ISbox[getByte( origState[2] , 1 )] , 1 )
                + putByte( ISbox[getByte( origState[1] , 0 )] , 0 )
    dstState[1] = putByte( ISbox[getByte( origState[1] , 3 )] , 3 )
                + putByte( ISbox[getByte( origState[0] , 2 )] , 2 )
                + putByte( ISbox[getByte( origState[3] , 1 )] , 1 )
                + putByte( ISbox[getByte( origState[2] , 0 )] , 0 )
    dstState[2] = putByte( ISbox[getByte( origState[2] , 3 )] , 3 )
                + putByte( ISbox[getByte( origState[1] , 2 )] , 2 )
                + putByte( ISbox[getByte( origState[0] , 1 )] , 1 )
                + putByte( ISbox[getByte( origState[3] , 0 )] , 0 )
    dstState[3] = putByte( ISbox[getByte( origState[3] , 3 )] , 3 )
                + putByte( ISbox[getByte( origState[2] , 2 )] , 2 )
                + putByte( ISbox[getByte( origState[1] , 1 )] , 1 )
                + putByte( ISbox[getByte( origState[0] , 0 )] , 0 )
end

---@param ints         integer
---@param output       integer
---@param outputOffset integer
---@param n            integer
---@return             table
local function intsToBytes( ints , output , outputOffset , n )
    n = n or #ints
    for i = 0 , n do
        for j = 0 , 3 do
            output[outputOffset + i*4 + (3 - j)] = getByte(ints[i], j)
        end
    end
    return output
end

---@param bytes table
---@param start integer
---@param n     integer
---@return      table
local function bytesToInts( bytes , start , n )
    local ints = {}
    for i = 0, n - 1 do
        ints[i] = putByte(bytes[start + (i*4)    ], 3)
                + putByte(bytes[start + (i*4) + 1], 2)
                + putByte(bytes[start + (i*4) + 2], 1)
                + putByte(bytes[start + (i*4) + 3], 0)
    end
    return ints
end

local aes = { }

---转换为加密秘钥
---@param key table
---@return    table
function aes.expandEncryptionKey( key )
    local keySchedule = {}
    local keyWords    = #key // 4

    if ( keyWords ~= 4 and keyWords ~= 6 and keyWords ~= 8 ) or (keyWords * 4 ~= #key) then
        print( "秘钥长度错误:", keyWords )
        return nil
    end

    keySchedule.round = keyWords + 6
    keySchedule.type  = 'encrypt'


    for i = 0 , keyWords - 1 do
        keySchedule[i] = putByte( key[i*4 + 1], 3 )
                       + putByte( key[i*4 + 2], 2 )
                       + putByte( key[i*4 + 3], 1 )
                       + putByte( key[i*4 + 4], 0 )
    end
    for i = keyWords , ( keySchedule.round + 1 ) * 4 - 1 do
        local tmp = keySchedule[i - 1]
        if i % keyWords == 0 then
            tmp = rotWord( tmp )
            tmp = subWord( tmp )
            local index = i // keyWords
            tmp = tmp ~ rCon[index]
        elseif keyWords > 6 and i % keyWords == 4 then
            tmp = subWord( tmp )
        end
        keySchedule[i] = keySchedule[ i - keyWords] ~ tmp
    end
    return keySchedule
end

---转换为解密秘钥
---@param key table
---@return    table
function aes.expandDecryptionKey( key )
    local keySchedule = aes.expandEncryptionKey( key )
    if keySchedule == nil then
        return nil
    end

    keySchedule.type = 'decrypt'

    for i = 4 , ( keySchedule.round + 1 ) * 4 - 5 do
        keySchedule[i] = invMixColumn( keySchedule[i] )
    end
    
    return keySchedule
end

---加密
function aes.encrypt( key , input , inputOffset , output , outputOffset )
    inputOffset  = inputOffset or 1
    output       = output or {}
    outputOffset = outputOffset or 1

    local state    = { }
    local tmpState = { }

    if key.type ~= 'encrypt' then
        print( '秘钥不是加密秘钥' )
        return
    end
    state = bytesToInts( input , inputOffset , 4 )
    addRoundKey( state , key , 0 )
    local round = 1
    while round < key.round - 1 do
        doRound( state , tmpState )
        addRoundKey( state , key , round )
        round = round + 1

        doRound( tmpState , state )
        addRoundKey( state , key , round )
        round = round + 1
    end
    doRound( state , tmpState )
    addRoundKey( state , key , round )
    round = round + 1

    doLastRound( tmpState , state )
    addRoundKey( state , key , round )
    
    return intsToBytes( state , output , outputOffset )
end

---解密
function aes.decrypt( key , input , inputOffset , output , outputOffset )
    inputOffset  = inputOffset or 1
    output       = output or {}
    outputOffset = outputOffset or 1

    local state    = { }
    local tmpState = { }

    if key.type ~= 'decrypt' then
        print( '秘钥不是解密秘密' )
        return
    end

    state = bytesToInts( input , inputOffset , 4 )
    addRoundKey( state , key , key.round )
    local round = key.round - 1
    while round > 2 do
        doInvRound( state , tmpState )
        addRoundKey( state , key , round )
        round = round - 1

        doInvRound( tmpState , state )
        addRoundKey( state , key , round )
        round = round - 1
    end
    doInvRound( state , tmpState )
    addRoundKey( state , key , round )
    round = round - 1

    doInvLastRound( tmpState , state )
    addRoundKey( state , key , round )
    
    return intsToBytes( state , output , outputOffset )
end

function aes.padByteString( data )
    local dataLength = #data;
    local random1 = math.random( 0 , 255 )
    local random2 = 255 - random1
    local prefix = string.char( random1,
                                random2,
                                random1,
                                random2,
                                getByte(dataLength, 3),
                                getByte(dataLength, 2),
                                getByte(dataLength, 1),
                                getByte(dataLength, 0) )
    data = prefix .. data
    local paddingLength = math.ceil(#data/16)*16 - #data;
    local padding = "";
    for i=1,paddingLength do
        padding = padding .. string.char( math.random( 0 , 255 ) )
    end
    return data .. padding;
end

function aes.unpadByteString(data)
    local random = { string.byte( data , 1 , 4 ) }
    if not ( random[1] == random[3] and random[2] == random[4] ) then
        return nil
    end
    local dataLength = putByte(string.byte( data , 5 ) , 3 )
                     + putByte(string.byte( data , 6 ) , 2 )
                     + putByte(string.byte( data , 7 ) , 1 )
                     + putByte(string.byte( data , 8 ) , 0 )
    return string.sub( data , 9 , 8 + dataLength )
end

---偏移量计算
---@param data table
---@param iv   table
local function xorIV(data, iv)
    for i = 1,16 do
        data[i] = data[i] ~ iv[i]
    end 
end

local ciphermode = { }

local enckey     = { }
local deckey     = { }

---私有加密
---@param key  any
---@param data string|table
---@param mode string
---@param iv   table
---@return     table
function ciphermode:encrypt( key , data , mode , iv )
    key = enckey[key] or key
    local result = { }
    for i = 1 , #data / 16 do
        local offset = ( i - 1 ) * 16 + 1
        local byteData = {string.byte( data , offset , offset + 15 )}
        if self['encrypt' .. mode] ~= nil then
            self['encrypt' .. mode]( self , key , byteData , iv )
        end
        for _ , v in ipairs( byteData ) do
            table.insert( result , v )
        end
    end
    return result
end

---私有解密
---@param key  table
---@param data table
---@param mode string
---@param iv   table
---@return     string
function ciphermode:decrypt( key , data , mode , iv )
    local keySched = enckey[key] or key
    if mode ~= 'OFB' and mode ~= 'CFB' then
        keySched = deckey[key] or key
    end
    local result = ""
    for i = 1 , #data / 16 do
        local offset   = ( i - 1 ) * 16 + 1
        local byteData = { table.unpack( data , offset , offset + 15 ) }
        if self['decrypt' .. mode] ~= nil then
            iv = self['decrypt' .. mode]( self , keySched , byteData , iv )
        end
        result = result .. string.char( table.unpack( byteData ) )
    end
    return result
end
---ECB加密
function ciphermode:encryptECB(keySched, byteData, iv)
	aes.encrypt(keySched, byteData, 1, byteData, 1)
end
---ECB解密
function ciphermode:decryptECB(keySched, byteData, iv) 
    aes.decrypt(keySched, byteData, 1, byteData, 1)
    return iv
end
---CBC加密
function ciphermode:encryptCBC(keySched, byteData, iv)
    xorIV(byteData, iv)
    aes.encrypt(keySched, byteData, 1, byteData, 1)
    for j = 1,16 do
        iv[j] = byteData[j]
    end
end
---CBC解密
function ciphermode:decryptCBC(keySched, byteData, iv) 
	local nextIV = {}
    for j = 1,16 do
        nextIV[j] = byteData[j]
    end
    aes.decrypt(keySched, byteData, 1, byteData, 1)
    xorIV(byteData, iv)
	return nextIV
end
---OFB加密
function ciphermode:encryptOFB(keySched, byteData, iv) 
    aes.encrypt(keySched, iv, 1, iv, 1)
    xorIV(byteData, iv)
end
---OFB解密
function ciphermode:decryptOFB(keySched, byteData, iv)
    aes.encrypt(keySched, iv, 1, iv, 1)
    xorIV(byteData, iv)
    return iv
end
--CFB加密
function ciphermode:encryptCFB(keySched, byteData, iv)
    aes.encrypt(keySched, iv, 1, iv, 1)
    xorIV(byteData, iv)
    for j = 1,16 do
        iv[j] = byteData[j]
    end
end
--CFB解密
function ciphermode:decryptCFB(keySched, byteData, iv) 
    local nextIV = {}
    for j = 1,16 do
        nextIV[j] = byteData[j]
    end
    aes.encrypt(keySched, iv, 1, iv, 1)
    xorIV(byteData, iv)
    return nextIV
end

---秘钥处理
---@param password  string
---@param keyLength number
---@return          table
local function pwToKey(password, keyLength)
    local name = password
    if enckey[name] == nil and deckey[name] == nil then
        local padLength = keyLength
        if keyLength == 24 then
            padLength = 32
        end
        if (padLength > #password) then
            local postfix = ""
            for i = 1,padLength - #password do
                postfix = postfix .. string.char(0)
            end
            password = password .. postfix
        else
            password = string.sub(password, 1, padLength)
        end
        
        local pwBytes = aes.expandEncryptionKey( { string.byte( password , 1 , #password ) } )
        password = ciphermode:encrypt( pwBytes , password , 'CBC' , { string.byte( password , 1 , 16 ) } )
        password = { table.unpack( password , 1 , padLength )}
   
        enckey[name] = aes.expandEncryptionKey( password )
        deckey[name] = aes.expandDecryptionKey( password )
    end
end

local function pwToIv( iv )
    if iv == nil then
        return {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
    end
    if type( iv ) == 'string' then
        iv = { iv:byte( 1 , 16 ) }
    end
    if type( iv ) ~= 'table' then
        return nil
    end
    if #iv > 16 then
        for i = #iv , 16 , -1 do
            iv[i] = nil
        end
    elseif #iv < 16 then
        for i = #iv , 16 , 1 do
            iv[i] = math.random( 0 , 255 )
        end
    end
    return iv
end

local encstring = {
    [0]= "\65" , "\66" , "\67" , "\68" , "\69" , "\70" , "\71" , "\72" , "\73" , "\74" , "\75" , "\76" , "\77" , "\78" , "\79" , "\80" ,
         "\81" , "\82" , "\83" , "\84" , "\85" , "\86" , "\87" , "\88" , "\89" , "\90" , "\97" , "\98" , "\99" , "\100", "\101", "\102",
         "\103", "\104", "\105", "\106", "\107", "\108", "\109", "\110", "\111", "\112", "\113", "\114", "\115", "\116", "\117", "\118",
         "\119", "\120", "\121", "\122", "\48" , "\49" , "\50" , "\51" , "\52" , "\53" , "\54" , "\55" , "\56" , "\57" , "\43" , "\47" , }

local decstring = { }
for k , v in pairs( encstring ) do
    decstring[v:byte( )] = k
end

local base64 = { }

-- base64转码
---@param str  string|table
---@param bool boolean
---@return any
base64.encode = function( str , bool )
    local byte     = str
    if type( str ) == 'string' then
        byte = { str:byte( 1 , #str )}
    end
    if type( byte ) ~= 'table' then
        return nil
    end
    local result = { }
    local len     = #byte
    local number  = len % 3
    local num     = 0
    for i = 1 , len , 3 do
        num = ( ( byte[i] or 0 ) << 16 ) + ( ( byte[i+1] or 0 ) << 8 ) + ( ( byte[i+2] or 0 ) << 0 )
        for j = 3 , 0 , -1 do
            local tmp = num >> ( j * 6 )
            table.insert( result , encstring[tmp & 0x3f])
        end
    end
    if number > 0 then
        for i = 3 - number , 1 , -1 do
            result[#result-i+1] = '='
        end
    end
    if bool then
        return result
    else
        return table.concat( result )
    end
end

-- base64解码
---@param  str  string|table
---@param  bool boolean
---@return any
base64.decode = function( str , bool )
    local byte     = str
    if type( str ) == 'string' then
        byte = { str:byte( 1 , #str ) }
    end
    if type( byte ) ~= 'table' then
        return nil
    end
    local result = { }
    local len    = #byte
    local num    = 0
    local number = 0
    str:gsub( '=' , function ( )
        number = number + 1
    end)
    if len % 4 ~= 0 then
        return nil
    end
    for i = 1 , len , 4 do
        num = ( ( decstring[byte[i]] or 0 ) << 18 ) + ( ( decstring[byte[i+1]] or 0 ) << 12 ) + ( ( decstring[byte[i+2]] or 0 ) << 6 ) + ( ( decstring[byte[i+3]] or 0 ) << 0 )
        for j = 2 , 0 , -1 do
            local tmp = num >> ( j * 8 )
            table.insert( result , tmp & 0xff )
        end
    end
    local max = #result
    if number > 0 then
        for i = number , 1 , -1 do
            result[max-i+1] = nil
        end
    end
    if bool then
        return result
    else
        return string.char( table.unpack( result ) )
    end
end

return {
    
    ---加密Api
    ---@param password  string       秘钥
    ---@param data      string       加密数据
    ---@param keyLength integer      秘钥长度(16,24,32)默认16
    ---@param mode      string       使用模式(ECB,CBC,OFB,CFB)默认CBC
    ---@param iv        string|table 偏移量(字符串或整数链表)默认{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
    ---@return          string
    encrypt = function ( data , password , keyLength , mode , iv )
        if data == nil or password == nil or data == '' or password == '' then
            return nil
        end
        mode      = mode or 'CBC'
        keyLength = keyLength or 16
        iv        = pwToIv( iv )
        pwToKey( password , keyLength )
        local paddedData = aes.padByteString( data )
        data = ciphermode:encrypt( password , paddedData , mode , iv )
        if paddedData == nil or #paddedData % 16 ~= 0 then
            return nil
        end
        return base64.encode( data )
    end,

    ---解密Api
    ---@param password  string       秘钥
    ---@param data      string       加密数据
    ---@param keyLength integer      秘钥长度(16,24,32)默认16
    ---@param mode      string       使用模式(ECB,CBC,OFB,CFB)默认CBC
    ---@param iv        string|table 偏移量(字符串或整数链表)默认{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
    ---@return          string
    decrypt = function ( data , password , keyLength , mode , iv )
        if data == nil or password == nil or data == '' or password == '' then
            return nil
        end
        mode      = mode or 'CBC'
        keyLength = keyLength or 16
        iv        = pwToIv( iv )
        pwToKey( password , keyLength )
        local paddedData = base64.decode( data , true )
        if paddedData == nil or #paddedData % 16 ~= 0 then
            return nil
        end
        data = ciphermode:decrypt( password , paddedData , mode , iv )
        return aes.unpadByteString( data )
    end,
}
